home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / CDragAcrossTable 1.0b1 / CDragAcrossTable.c next >
Text File  |  1993-11-04  |  17KB  |  684 lines

  1. /******************************************************************************
  2.  CDragAcrossTable.c
  3.  
  4.     This is an examples class that works with CDragAcrossTask to drag the
  5.     selected cells to another postion within the current table or another
  6.     CDragAcrossTable in the applicaiton.
  7.     
  8.     This is a subclass of CTable, but it can be made a subclass of any CTable
  9.     subclass, such as CArrayPane. Too bad I can't/don't use 
  10.     multiple-inheritance.
  11.  
  12.     AUTHOR: Andrew_Gilmartin@Brown.Edu
  13.     MODIFIED: 93-11-04
  14.  
  15.     Copyright (C) 1993 by Brown University. All rights reserved.
  16.  
  17.     Permission is granted to any individual or institution to use, copy,
  18.     or redistribute the binary version of this software and its
  19.     documentation provided this notice and the copyright notices are
  20.     retained.  Permission is granted to any individual or non-profit
  21.     institution to use, copy, modify, or redistribute the source files
  22.     of this software provided this notice and the copyright notices are
  23.     retained.  This software may not be distributed for profit, either
  24.     in original form or in derivative works, nor can the source be
  25.     distributed to other than an individual or a non-profit institution.
  26.     Any  individual or group interested in seeing and/or using these
  27.     source files but who are prevented from doing so by the above
  28.     constraints should contact Don Wolfe, Vice-President for Computer 
  29.     Systems at Brown University, (401) 863-7247, for possible
  30.     software licensing of the source developed at Brown.
  31.  
  32.     Brown University and Andrew James Gilmartin make no representations
  33.     about the suitability of this software for any purpose.
  34.  
  35.      BROWN UNIVERSITY AND ANDREW JAMES GILMARTIN GIVE NO WARRANTY, EITHER
  36.     EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
  37.     INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
  38.     WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  39.  
  40. ******************************************************************************/
  41.  
  42. #include "ForgetRgn.h"
  43. #include "CDragAcrossTask.h"
  44. #include "CDragAcrossTable.h"
  45.  
  46. #define IS_EVEN( _n ) \
  47.     ( ( (_n) & 0x01 ) == 0 )
  48.  
  49. enum { kBoundarySize = 4 }; // used by DragRowBoundary() & DrawColBoundary()
  50.  
  51. enum { kAutoScrollSlop = 10 }; // used by ShouldScroll()
  52.     
  53. Boundary kEmptyBoundary = { -1, -1 };
  54.  
  55.  
  56.  
  57. /******************************************************************************
  58.  IDragAcrossTable
  59.  
  60.     Initilaize the drag across table.
  61. ******************************************************************************/
  62.  
  63. void CDragAcrossTable::IDragAcrossTable
  64.     ( CView* anEnclosure
  65.     , CBureaucrat* aSupervisor
  66.     , short aWidth
  67.     , short aHeight
  68.     , short aHEncl
  69.     , short aVEncl
  70.     , SizingOption aHSizing
  71.     , SizingOption aVSizing )
  72. {
  73.     ITable
  74.         ( anEnclosure
  75.         , aSupervisor
  76.         , aWidth
  77.         , aHeight
  78.         , aHEncl
  79.         , aVEncl
  80.         , aHSizing
  81.         , aVSizing );
  82.  
  83.     itsSelectedBoundaries = kEmptyBoundary;
  84.  
  85. } /* IDragAcrossTable */
  86.  
  87.  
  88.  
  89. /******************************************************************************
  90.  MoveSelection
  91.  
  92.     This method is called by CDragAcrossTask should the user select a boundary
  93.     to move the selection to.
  94. ******************************************************************************/
  95.  
  96. void CDragAcrossTable::MoveSelection( CDragAcrossTable* toTable, Boundary toBoundary )
  97. {
  98.     /* nop */
  99.  
  100. } /* MoveSelection */
  101.  
  102.  
  103.  
  104. /******************************************************************************
  105.  DoClick
  106.  
  107.     Did the user click to drag or click to select? Act approp.
  108. ******************************************************************************/
  109.  
  110. void CDragAcrossTable::DoClick( Point hitPt, short modifierKeys, long when )
  111. {
  112.     CDragAcrossTask* dragTask;
  113.     Cell hitCell;
  114.     LongPt pt;
  115.     Point startPt;
  116.  
  117.     QDToFrame( hitPt, &pt );
  118.     
  119.     if ( PtInLongRect( &pt, &bounds ) )
  120.     {
  121.         if ( HitDragZone( hitPt, modifierKeys ) )
  122.         {
  123.     
  124.             dragTask = MakeGlobalMouseTask();
  125.                         
  126.             FrameToGlobal( &pt, &startPt );
  127.             TrackGlobalMouse( dragTask, startPt );
  128.  
  129.             ForgetObject( dragTask );
  130.         }
  131.         else
  132.         {
  133.             inherited::DoClick( hitPt, modifierKeys, when );
  134.         }
  135.     }
  136.     else
  137.     {
  138.         ClickOutsideBounds( hitPt, modifierKeys, when);
  139.     }
  140.  
  141. } /* DoClick */
  142.  
  143.  
  144.  
  145. /******************************************************************************
  146.  HitDragZone
  147.  
  148.     Called by DoClick() to determine if the user has clicked in the "drag 
  149.     zone."
  150. ******************************************************************************/
  151.  
  152. Boolean CDragAcrossTable::HitDragZone( Point hitPt, short modifierKeys )
  153. {
  154.     return ( modifierKeys & controlKey ) != 0;
  155.  
  156. } /* HitDragZone */
  157.  
  158.  
  159.  
  160. /******************************************************************************
  161.  MakeGlobalMouseTask
  162.  
  163.     Create the global mouse task. NOTE: aNameIndex of 130 is the TCL default.
  164. ******************************************************************************/
  165.  
  166. CDragAcrossTask* CDragAcrossTable::MakeGlobalMouseTask( void )
  167. {
  168.     CDragAcrossTask* dragTask = NULL;
  169.     
  170.     TRY
  171.     {
  172.         dragTask = new CDragAcrossTask;
  173.         dragTask->IDragAcrossTask( this, GetSelectionRgn(), 130 );
  174.     }
  175.     CATCH
  176.     {
  177.         ForgetObject( dragTask );
  178.     }
  179.     ENDTRY
  180.  
  181.     return dragTask;
  182.  
  183. } /* MakeGlobalMouseTask */
  184.  
  185.  
  186.  
  187. /******************************************************************************
  188.  Draw
  189.  
  190.     Draw the content plus the selected boundaries. Assume the pane is
  191.     already prepared.
  192. ******************************************************************************/
  193.  
  194. void CDragAcrossTable::Draw( Rect *area )
  195. {
  196.     inherited::Draw( area );
  197.  
  198.         /* Update the boundary selection */
  199.  
  200.     if ( ! EqualPt( itsSelectedBoundaries, kEmptyBoundary ) )
  201.     {
  202.         DrawColBoundary( itsSelectedBoundaries );
  203.         DrawRowBoundary( itsSelectedBoundaries );
  204.     }
  205.  
  206. } /* Draw */
  207.  
  208.  
  209.  
  210. /******************************************************************************
  211.  DrawRowBoundary
  212.  
  213.     Hilight the row boundary. Assumes the pane is already prepared.
  214. ******************************************************************************/
  215.  
  216. void CDragAcrossTable::DrawRowBoundary( Boundary boundaries )
  217. {
  218.     LongRect pixels;
  219.     Rect visPixels;
  220.     short col;
  221.     short row;
  222.  
  223.         /* Make sure there is a row boundary */
  224.  
  225.     if ( boundaries.v == kEmptyBoundary.v )
  226.         return;
  227.  
  228.         /* Get boundary's horizontal position and length */
  229.  
  230.     col = boundaries.h / 2;
  231.  
  232.     pixels.left  = GetColStart( col );
  233.     pixels.right = pixels.left + GetColWidth( col );
  234.  
  235.     pixels.left  += kBoundarySize / 2, 
  236.     pixels.right -= kBoundarySize / 2; // HACK: Makes it look a little better
  237.  
  238.         /* Get boundary's vertical position and height */
  239.  
  240.     row = boundaries.v / 2;
  241.  
  242.     if ( IS_EVEN( boundaries.v ) )
  243.     {
  244.             // Boundary at the top of the cell
  245.             
  246.         pixels.top = GetRowStart( row ) - kBoundarySize / 2;
  247.         pixels.bottom = pixels.top + kBoundarySize;    
  248.     }
  249.     else
  250.     {
  251.             // Boundary at the bottom of the cell
  252.  
  253.         pixels.bottom 
  254.             = GetRowStart( row ) 
  255.             + GetRowHeight( row ) 
  256.             + kBoundarySize / 2;
  257.         pixels.top = pixels.bottom - kBoundarySize;    
  258.     }
  259.  
  260.         /* Draw boundary rect */
  261.  
  262.     if ( SectAperture( &pixels, &visPixels ) )
  263.     {
  264.         SetHiliteMode(); // Invert with user's hilite color
  265.         InvertRect( &visPixels );
  266.     }
  267.  
  268. } /* DrawRowBoundary */
  269.  
  270.  
  271.  
  272. /******************************************************************************
  273.  DrawColBoundary
  274.  
  275.     Hilight the column boundary. Assumes the pane is already prepared.
  276. ******************************************************************************/
  277.  
  278. void CDragAcrossTable::DrawColBoundary( Boundary boundaries )
  279. {
  280.     LongRect pixels;
  281.     Rect visPixels;
  282.     short col;
  283.     short row;
  284.  
  285.         /* Make sure there is a column boundary */
  286.  
  287.     if ( boundaries.h == kEmptyBoundary.h )
  288.         return;
  289.  
  290.         /* Get boundary's vertical position and height */
  291.  
  292.     row = boundaries.v / 2;
  293.     
  294.     pixels.top  = GetRowStart( row );
  295.     pixels.bottom = pixels.top + GetRowHeight( row );
  296.  
  297.     pixels.top    -= kBoundarySize / 2, 
  298.     pixels.bottom += kBoundarySize / 2; // HACK: Makes it look a little better
  299.  
  300.         /* Get boundary's horizontal position and length */
  301.  
  302.     col = boundaries.h / 2;
  303.  
  304.     if ( IS_EVEN( boundaries.h ) )
  305.     {
  306.             // Boundary to the left of the column
  307.  
  308.         pixels.left  = GetColStart( col ) - kBoundarySize / 2;
  309.         pixels.right = pixels.left + kBoundarySize;
  310.     }
  311.     else
  312.     {
  313.             // Boundary to the right of the column
  314.  
  315.         pixels.right 
  316.             = GetColStart( col ) 
  317.             + GetColWidth( col ) 
  318.             + kBoundarySize / 2;
  319.         pixels.left = pixels.right - kBoundarySize;    
  320.     }
  321.  
  322.         /* Draw boundary rect */
  323.  
  324.     if ( SectAperture( &pixels, &visPixels ) )
  325.     {
  326.         SetHiliteMode(); // Invert with user's hilite color
  327.         InvertRect( &visPixels );
  328.     }
  329.  
  330. } /* DrawColBoundary */
  331.  
  332.  
  333.  
  334. /******************************************************************************
  335.  SelectBoundaries
  336.  
  337.     Select the cell boundaries. Assumes the pane is already prepared.    
  338. ******************************************************************************/
  339.  
  340. void CDragAcrossTable::SelectBoundaries( Boundary boundaries )
  341. {
  342.     if ( ! EqualPt( itsSelectedBoundaries, boundaries ) )
  343.     {
  344.             /*If necessary deselect/draw the previous boundaries */
  345.             
  346.         if ( ! EqualPt( itsSelectedBoundaries, kEmptyBoundary ) )
  347.         {
  348.             DrawColBoundary( itsSelectedBoundaries );
  349.             DrawRowBoundary( itsSelectedBoundaries );
  350.         }
  351.  
  352.         itsSelectedBoundaries = boundaries;
  353.  
  354.             /* select/draw new boundaries */
  355.     
  356.         DrawColBoundary( itsSelectedBoundaries );
  357.         DrawRowBoundary( itsSelectedBoundaries );
  358.     }
  359.  
  360. } /* SelectBoundaries */
  361.  
  362.  
  363.  
  364. /******************************************************************************
  365.  FindBoundaries
  366.  
  367.     Find the boundaries what were hit.
  368. ******************************************************************************/
  369.  
  370. void CDragAcrossTable::FindBoundaries( LongPt* hitPt, Boundary* hitBoundary )
  371. {
  372.     hitBoundary->v = FindRowBoundary( hitPt->v );
  373.     hitBoundary->h = FindColBoundary( hitPt->h );
  374.  
  375. } /* FindBoundaries */
  376.  
  377.  
  378.  
  379. /******************************************************************************
  380.  FindRowBoundary
  381.  
  382.     Return the row boundary index for the given vertical offset. The
  383.     boundary index indicates both the row and the side of the row. To
  384.     determine the row divide the index by two. To determine which side
  385.     test the index for even-ness; an even index means the boundary is at the
  386.     top and an odd index means at the bottom.    
  387. ******************************************************************************/
  388.  
  389. short CDragAcrossTable::FindRowBoundary( long vLoc )
  390. {
  391.     short row;
  392.     long middle;
  393.  
  394.     if ( vLoc >= bounds.bottom )
  395.     {
  396.         row = ( tableBounds.bottom * 2 ) + 1;
  397.     }
  398.     else
  399.     {
  400.             /* Find the row the vLoc is in. */
  401.             
  402.         vLoc -= topLeftIndent.v;
  403.         row = itsRows->FindSum( vLoc ) - 1;
  404.         if ( row < 0 )
  405.             row = 0;
  406.  
  407.             /* Is the boundary to the top or bottom. Which side of the middle? */
  408.  
  409.         middle = GetRowStart( row ) + GetRowHeight( row ) / 2;
  410.  
  411.         if ( vLoc < middle )
  412.             row = row * 2; // top
  413.         else
  414.             row = row * 2 + 1; // bottom
  415.     }
  416.     
  417.     return row;
  418.     
  419. } /* FindRowBoundary */
  420.  
  421.  
  422.  
  423. /******************************************************************************
  424.  FindColBoundary
  425.  
  426.     Return the column boundary index for the given horizontal offset. The
  427.     boundary index indicates both the column and the side of the column. To
  428.     determine the column divide the index by two. To determine which side
  429.     test the index for even-ness; an even index means the boundary is to the
  430.     left and an odd index means to the left.
  431. ******************************************************************************/
  432.  
  433. short CDragAcrossTable::FindColBoundary( long hLoc )
  434. {
  435.     short col;
  436.     long middle;
  437.  
  438.     if ( hLoc >= bounds.right )
  439.     {
  440.         col = ( tableBounds.right * 2 ) + 1;
  441.     }
  442.     else
  443.     {
  444.             /* Find the column the hLoc is in. */
  445.             
  446.         hLoc -= topLeftIndent.h;
  447.         col = itsCols->FindSum( hLoc ) - 1;
  448.         if ( col < 0 )
  449.             col = 0;
  450.  
  451.             /* Is the boundary to the left or right. Which side of the middle? */
  452.  
  453.         middle = GetColStart( col ) + GetColWidth( col ) / 2;
  454.         
  455.         if ( hLoc < middle )
  456.             col = col * 2; // left
  457.         else
  458.             col = col * 2 + 1; // right
  459.     }
  460.     
  461.     return col;
  462.     
  463. } /* FindColBoundary */
  464.  
  465.  
  466.  
  467. /******************************************************************************
  468.  GetSelectionRgn
  469.  
  470.     Return a region that represents the selection. This methed is used by
  471.     CDragAcrossTask.
  472. ******************************************************************************/
  473.  
  474. RgnHandle CDragAcrossTable::GetSelectionRgn( void )
  475. {
  476.     RgnHandle cellRgn = NULL;
  477.     RgnHandle selectionRgn = NULL;
  478.     LongRect cellRect;
  479.     Rect cellQDRect;
  480.     Cell cell;
  481.     
  482.     TRY
  483.     {
  484.         cellRgn = NewRgn();    
  485.         selectionRgn = NewRgn();
  486.  
  487.         Prepare();
  488.  
  489.             /* Brute force iteration over the whole table. I can't seem to figure
  490.                 out how to get GetSelect() to work. */
  491.  
  492.         for ( cell.h = tableBounds.left; cell.h < tableBounds.right + 1; cell.h++ )
  493.         {
  494.             for ( cell.v = tableBounds.top; cell.v < tableBounds.bottom + 1; cell.v++ )
  495.             {
  496.                 if ( IsSelected( cell ) )
  497.                 {
  498.                         /* Make cell region */
  499.                         
  500.                     GetCellRect( cell, &cellRect );
  501.                     InsetLongRect( &cellRect, 1, 1 );
  502.                     FrameToGlobalR( &cellRect, &cellQDRect );
  503.                     RectRgn( cellRgn, &cellQDRect );
  504.  
  505.                         /* Add cell region to selection region */
  506.  
  507.                     UnionRgn( cellRgn, selectionRgn, selectionRgn );
  508.                 }
  509.             }
  510.         }
  511.  
  512.         DisposeRgn( cellRgn );
  513.     }
  514.     CATCH
  515.     {
  516.         ForgetRgn( cellRgn );
  517.         ForgetRgn( selectionRgn );
  518.     }
  519.     ENDTRY
  520.  
  521.     return selectionRgn;
  522.  
  523. } /* GetSelectionRgn */
  524.  
  525.  
  526.  
  527. /******************************************************************************
  528.  AutoScroll
  529.  
  530.     Scroll the table if necessary. See ShouldScroll() for more information
  531.     about scrolling with CDragAcrossTable.
  532. ******************************************************************************/
  533.  
  534. Boolean CDragAcrossTable::AutoScroll( LongPt* mouseLoc )
  535. {
  536.     Point theDelta;
  537.     
  538.     if ( ShouldScroll( mouseLoc, &theDelta ) )
  539.     {
  540.         Scroll( theDelta.h, theDelta.v, TRUE );
  541.         if ( itsScrollPane != NULL )
  542.         {
  543.             itsScrollPane->Calibrate();
  544.         }
  545.         Prepare(); 
  546.         
  547.         return TRUE;
  548.     } 
  549.     else
  550.     {
  551.         return FALSE;
  552.     }
  553.  
  554. } /* AutoScroll */
  555.  
  556.  
  557.  
  558. /******************************************************************************
  559.  ShouldScroll
  560.  
  561.     Determine whether the table should scroll given the current mouse location.
  562.     Return true or false approp. plus the scrolling delta. (Code taken from
  563.     CPanoram::AutoScroll().)
  564.  
  565.     To aid scrolling when the mouse is within the table, this override checks
  566.     if the mouseLoc is near the edge of the frame. Near the edge is defined
  567.     as kAutoScrollSlop. The reason for scrolling when the mouse is in the
  568.     table is that when CDragAcrossTask has content the current table will lose
  569.     focus when the mouse moves outside of the frame. Having the slop allows 
  570.     the user to autoscroll within the table.
  571. ******************************************************************************/
  572.  
  573. Boolean CDragAcrossTable::ShouldScroll( LongPt* mouseLoc, Point* delta )
  574. {
  575.     short        hDelta = 0;
  576.     short        vDelta = 0;
  577.     short        hSpan;
  578.     short        vSpan;
  579.     short        hStep = 1;
  580.     short        vStep = 1;
  581.  
  582.     GetFrameSpan(&hSpan, &vSpan);
  583.  
  584.     GetSteps( &hStep, &vStep );            // TCL 1.1.3 11/30/92 BF    
  585.     
  586.     if (mouseLoc->h < frame.left + kAutoScrollSlop ) {
  587.         hDelta = Max(-hStep, bounds.left - position.h);
  588.         if (hDelta > 0) {
  589.             hDelta = 0;
  590.         }
  591.     } else if (mouseLoc->h > frame.right - kAutoScrollSlop ) {
  592.         hDelta = Min(hStep, bounds.right - position.h - hSpan);
  593.         if (hDelta < 0) {
  594.             hDelta = 0;
  595.         }
  596.     }
  597.     
  598.     if (mouseLoc->v < frame.top + kAutoScrollSlop ) {
  599.         vDelta = Max(-vStep, bounds.top - position.v);
  600.         if (vDelta > 0) {
  601.             vDelta = 0;
  602.         }
  603.     } else if (mouseLoc->v > frame.bottom - kAutoScrollSlop ) {
  604.         vDelta = Min(vStep, bounds.bottom - position.v - vSpan);
  605.         if (vDelta < 0) {
  606.             vDelta = 0;
  607.         }
  608.     }
  609.     
  610.     if ( ( hDelta != 0 ) || ( vDelta != 0 ) )
  611.     {
  612.         if ( delta != NULL ) // Some callers might not care about the actual delta
  613.             SetPt( delta, hDelta, vDelta );
  614.         return(TRUE);
  615.     }
  616.     else
  617.     {
  618.         return(FALSE);
  619.     }
  620.  
  621. } /* ShouldScroll */
  622.  
  623.  
  624.  
  625. /******************************************************************************
  626.  TrackGlobalMouse
  627.  
  628.     Similar to TrackMouse() but all the coordinates are in the global (ie
  629.     CDesktop) coordinate system. (Perhaps I should generalize this to be any
  630.     view's coordinate system.
  631. ******************************************************************************/
  632.  
  633. void CDragAcrossTable::TrackGlobalMouse( CGlobalMouseTask* aTask, Point startPt )
  634. {
  635.     Point currPt;
  636.     Point prevPt;
  637.     EventRecord macEvent;
  638.  
  639.     currPt = prevPt = startPt;
  640.  
  641.     aTask->BeginTracking( startPt );
  642.     
  643.     while ( StillDown() )
  644.     {
  645.         gDesktop->Prepare();
  646.         GetMouse( &currPt );
  647.         
  648.         aTask->KeepTracking( currPt, prevPt, startPt );
  649.         prevPt = currPt;
  650.     }
  651.     
  652.     gDesktop->Prepare();
  653.     if ( OSEventAvail( mUpMask, &macEvent ) )
  654.     {
  655.         currPt = macEvent.where;
  656.     }
  657.     
  658.     aTask->EndTracking( currPt, prevPt, startPt );
  659.  
  660. } /* TrackGlobalMouse */
  661.  
  662.  
  663.  
  664. /******************************************************************************
  665.  FrameToGlobal
  666.  
  667.     Convert a LongPt from Frame to Global coordinates.
  668. ******************************************************************************/
  669.  
  670. void CDragAcrossTable::FrameToGlobal( LongPt* framePt, Point* globalPt )
  671. {
  672.     Point offset;
  673.     
  674.     LongToQDPt( framePt, globalPt);
  675.     
  676.     offset = topLeft((**((WindowPeek)macPort)->contRgn).rgnBBox);
  677.     
  678.     globalPt->v += offset.v - vOrigin;
  679.     globalPt->h += offset.h - hOrigin;
  680.  
  681. } /* FrameToGlobal */
  682.  
  683.  
  684.